import {
    Component,
    ComponentType,
    ErrorInfo,
    FunctionComponent,
    PropsWithChildren,
    ReactElement,
    ReactNode
} from 'react';

declare function FallbackRender(props: FallbackProps): ReactNode;

export type FallbackProps = {
    error: string;
    resetErrorBoundary: (...args: any[]) => void;
};

type ErrorBoundarySharedProps = PropsWithChildren<{
    onError?: (error: Error, info: ErrorInfo) => void;
    onReset?: (
        details:
            | { reason: 'imperative-api'; args: any[] }
            | { reason: 'keys'; prev: any[] | undefined; next: any[] | undefined }
    ) => void;
    resetKeys?: any[];
}>;
export type FallbackComponentType = ComponentType<FallbackProps>;
export type FallbackRenderType = typeof FallbackRender;
export type FallBackType = ReactElement<
    unknown,
    string | FunctionComponent | typeof Component
> | null;
export type ErrorBoundaryPropsWithComponent = ErrorBoundarySharedProps & {
    fallback?: never;
    fallbackComponent: FallbackComponentType;
    fallbackRender?: never;
};

export type ErrorBoundaryPropsWithRender = ErrorBoundarySharedProps & {
    fallback?: never;
    fallbackComponent?: never;
    fallbackRender: FallbackRenderType;
};

export type ErrorBoundaryPropsWithFallback = ErrorBoundarySharedProps & {
    fallback: FallBackType;
    fallbackComponent?: never;
    fallbackRender?: never;
};

export type ErrorBoundaryProps =
    | ErrorBoundaryPropsWithFallback
    | ErrorBoundaryPropsWithComponent
    | ErrorBoundaryPropsWithRender;
